package cn.regexp.common.core.web.interceptor;


import cn.regexp.common.core.constants.CommonConstants;
import cn.regexp.common.core.domain.UserInfo;
import cn.regexp.common.core.web.CommonCodeMsg;
import cn.regexp.common.core.web.Result;
import cn.regexp.common.core.web.anno.RequireLogin;
import cn.regexp.common.redis.enums.CommonRedisKeyEnum;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.lang.NonNull;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author Regexpei
 * @date 2024/7/5 21:12
 * @description 登录请求拦截器
 */
public class RequireLoginInterceptor implements HandlerInterceptor {

    private final StringRedisTemplate redisTemplate;

    public RequireLoginInterceptor(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
                             @NonNull Object handler) throws Exception {
        // 判断请求是否为处理方法
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            String feignRequest = request.getHeader(CommonConstants.FEIGN_REQUEST_KEY);
            // 如果 feignRequest 为空，则直接放行
            // 如果 feignRequest 为 Feign 调用，则直接放行
            // 如果请求方法没有登录标记，则直接放行
            if (!StringUtils.isEmpty(feignRequest) && CommonConstants.FEIGN_REQUEST_FALSE.equals(
                    feignRequest) && handlerMethod.getMethodAnnotation(RequireLogin.class) != null) {
                response.setContentType("application/json;charset=utf-8");
                // 获取 token 信息
                String token = request.getHeader(CommonConstants.TOKEN_NAME);
                // 如果 token 为空，则代表没有登录或登录超时
                if (StringUtils.isEmpty(token)) {
                    response.getWriter().write(JSON.toJSONString(Result.error(CommonCodeMsg.TOKEN_INVALID)));
                    return false;
                }
                UserInfo userInfo = JSON.parseObject(
                        redisTemplate.opsForValue().get(CommonRedisKeyEnum.USER_TOKEN.getRealKey(token)),
                        UserInfo.class);
                // 如果 userInfo 为空，则代表没有登录或登录超时
                if (userInfo == null) {
                    response.getWriter().write(JSON.toJSONString(Result.error(CommonCodeMsg.TOKEN_INVALID)));
                    return false;
                }
                // 获取在过滤器中放入请求头中的真实 IP
                String ip = request.getHeader(CommonConstants.REAL_IP);
                // 将 redis 中用户的登录 IP 与 本次请求的真实 IP 进行比对，若比对失败，则说明登录 IP 发生改变
                if (!userInfo.getLoginIp().equals(ip)) {
                    response.getWriter().write(JSON.toJSONString(Result.error(CommonCodeMsg.LOGIN_IP_CHANGE)));
                    return false;
                }
            }
        }
        return true;
    }
}

